package com.ruoyi.auth.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Maps;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.commons.collections4.MapUtils;
import org.tiankafei.common.constants.CommonConstants;
import org.tiankafei.common.model.ApiResult;
import org.tiankafei.common.utils.JacksonUtil;
import org.tiankafei.common.utils.Sm2Utils;

/**
 * @author tiankafei
 */
@Slf4j
public abstract class OkHttpUtils {

    private final static OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
            // 设置读取超时时间
            .readTimeout(10, TimeUnit.SECONDS)
            // 设置写的超时时间
            .writeTimeout(10, TimeUnit.SECONDS)
            // 设置连接超时时间
            .connectTimeout(10, TimeUnit.SECONDS)
            .build();

    public static final MediaType APPLICATION_JSON = MediaType.parse("application/json; charset=utf-8");

    /**
     * post请求
     *
     * @param url
     * @return
     * @throws IOException
     */
    public static <T> ApiResult<T> postRequestBody(String url, TypeReference<ApiResult<T>> typeReference) throws IOException {
        return postRequestBody(url, null, typeReference);
    }

    public static <T> ApiResult<T> postRequestBody(String url, Object paramObject, TypeReference<ApiResult<T>> typeReference) throws IOException {
        return postRequestBody(url, paramObject, "", typeReference);
    }

    /**
     * post请求
     *
     * @param url
     * @param paramObject
     * @return
     * @throws IOException
     */
    public static <T> ApiResult<T> postRequestBody(String url, Object paramObject, String token, TypeReference<ApiResult<T>> typeReference) throws IOException {
        String param = paramObject == null ? "{}" : JacksonUtil.toJSONString(paramObject);
        Request request = new Request.Builder()
                .addHeader("content-type", "application/json")
                .addHeader(CommonConstants.TENANT_ID, CommonConstants.DEFAULT_TENANT_ID)
                .addHeader(CommonConstants.DEFAULT_KEY, Sm2Utils.encrypt(CommonConstants.DEFAULT_VALUE))
                .addHeader(CommonConstants.HEADER_TOKEN, token)
                .url(url)
                .post(RequestBody.create(APPLICATION_JSON, param))
                .build();

        log.info("To Server Send Begin........");
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("Unexpected code " + response);
        }
        String result = response.body().string();
        log.info("Client Received........");
        return JacksonUtil.parseObject(result, typeReference);
    }

    /**
     * put请求
     *
     * @param url
     * @return
     * @throws IOException
     */
    public static <T> ApiResult<T> putRequestBody(String url, TypeReference<ApiResult<T>> typeReference) throws IOException {
        return putRequestBody(url, null, typeReference);
    }

    /**
     * put请求
     *
     * @param url
     * @param paramObject
     * @return
     * @throws IOException
     */
    public static <T> ApiResult<T> putRequestBody(String url, Object paramObject, TypeReference<ApiResult<T>> typeReference) throws IOException {
        String param = paramObject == null ? "{}" : JacksonUtil.toJSONString(paramObject);

        RequestBody body = RequestBody.create(param, APPLICATION_JSON);
        Request request = new Request.Builder()
                .addHeader("content-type", "application/json")
                .addHeader(CommonConstants.TENANT_ID, CommonConstants.DEFAULT_TENANT_ID)
                .addHeader(CommonConstants.DEFAULT_KEY, Sm2Utils.encrypt(CommonConstants.DEFAULT_VALUE))
                .url(url)
                .put(body)
                .build();

        log.info("To Server Send Begin........");
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("Unexpected code " + response);
        }
        String result = response.body().string();
        log.info("Client Received........");
        return JacksonUtil.parseObject(result, typeReference);
    }

    /**
     * post form 请求
     *
     * @param url
     * @param paramMap
     * @return
     * @throws IOException
     */
    public static <T> ApiResult<T> postFormBody(String url, Map<String, String> paramMap, TypeReference<ApiResult<T>> typeReference) throws IOException {
        FormBody.Builder formBody = new FormBody.Builder();

        if (MapUtils.isNotEmpty(paramMap)) {
            Set<Map.Entry<String, String>> entries = paramMap.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                formBody.add(entry.getKey(), entry.getValue());
            }
        }
        Request request = new Request.Builder()
                .addHeader("content-type", "application/json")
                .addHeader(CommonConstants.TENANT_ID, CommonConstants.DEFAULT_TENANT_ID)
                .addHeader(CommonConstants.DEFAULT_KEY, Sm2Utils.encrypt(CommonConstants.DEFAULT_VALUE))
                .url(url)
                .post(formBody.build())
                .build();
        log.info("To Server Send Begin........");
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("Unexpected code " + response);
        }
        String result = response.body().string();
        log.info("Client Received........");
        return JacksonUtil.parseObject(result, typeReference);
    }

    /**
     * get请求
     *
     * @param url
     * @return
     * @throws IOException
     */
    public static <T> ApiResult<T> get(String url, TypeReference<ApiResult<T>> typeReference) throws IOException {
        return get(url, Maps.newHashMap(), typeReference);
    }

    /**
     * get请求
     *
     * @param url
     * @param paramMap
     * @return
     * @throws IOException
     */
    public static <T> ApiResult<T> get(String url, Map<String, String> paramMap, TypeReference<ApiResult<T>> typeReference) throws IOException {
        StringBuffer urlBuffer = new StringBuffer(url);
        if (MapUtils.isNotEmpty(paramMap)) {
            int index = 0;
            Set<Map.Entry<String, String>> entries = paramMap.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                if (index == 0) {
                    urlBuffer.append("?");
                } else {
                    urlBuffer.append("&");
                }
                urlBuffer.append(entry.getKey()).append("=").append(entry.getValue());
                index++;
            }
        }
        Request request = new Request.Builder()
                .addHeader("content-type", "application/json")
                .addHeader(CommonConstants.TENANT_ID, CommonConstants.DEFAULT_TENANT_ID)
                .addHeader(CommonConstants.DEFAULT_KEY, Sm2Utils.encrypt(CommonConstants.DEFAULT_VALUE))
                .url(urlBuffer.toString())
                .build();
        log.info("To Server Send Begin........");
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("Unexpected code " + response);
        }
        String result = response.body().string();
        log.info("Client Received........");
        return JacksonUtil.parseObject(result, typeReference);
    }

    /**
     * delete请求
     *
     * @param url
     * @return
     * @throws IOException
     */
    public static <T> ApiResult<T> delete(String url, TypeReference<ApiResult<T>> typeReference) throws IOException {
        Request request = new Request.Builder()
                .addHeader("content-type", "application/json")
                .addHeader(CommonConstants.TENANT_ID, CommonConstants.DEFAULT_TENANT_ID)
                .addHeader(CommonConstants.DEFAULT_KEY, Sm2Utils.encrypt(CommonConstants.DEFAULT_VALUE))
                .url(url)
                .delete()
                .build();
        log.info("To Server Send Begin........");
        Response response = okHttpClient.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("Unexpected code " + response);
        }
        String result = response.body().string();
        log.info("Client Received........");
        return JacksonUtil.parseObject(result, typeReference);
    }

}
